package com.wnxy.pms.product.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wnxy.pms.common.api.Result;
import com.wnxy.pms.order.client.OrderFeginClient;
import com.wnxy.pms.order.client.dto.OrderDto;
import com.wnxy.pms.product.core.config.OrderProducer;
import com.wnxy.pms.product.core.constant.OrderConstant;
import com.wnxy.pms.product.core.constant.PromotionStatus;
import com.wnxy.pms.product.core.constant.RedisConstant;
import com.wnxy.pms.product.core.dto.OrderPayDto;
import com.wnxy.pms.product.core.entity.Product;
import com.wnxy.pms.product.core.entity.PromotionSeckill;
import com.wnxy.pms.product.core.exception.Asserts;
import com.wnxy.pms.product.core.mapper.ProductMapper;
import com.wnxy.pms.product.core.mapper.PromotionSeckillMapper;
import com.wnxy.pms.product.core.service.IPromotionSeckillService;
import com.wnxy.pms.product.core.vo.OrderVo;
import com.wnxy.pms.product.core.vo.PaymentVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 秒杀活动表 服务实现类
 * </p>
 *
 * @author Jet
 * @since 2022-06-06
 */
@Service
@Slf4j
public class PromotionSeckillServiceImpl extends ServiceImpl<PromotionSeckillMapper, PromotionSeckill> implements IPromotionSeckillService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OrderFeginClient orderFeginClient;
    @Autowired(required = false)
    private ProductMapper productMapper;

    @Autowired
    private OrderProducer orderProducer;

    @Override
    public List<Map<String, Object>> selectStoreByStatus(Integer waitStatus) {
        return baseMapper.selectStoreByStatus(waitStatus);
    }

    @Override
    public OrderVo submitOrder(String userId, Integer promotionId) {
        //1. 根据秒杀活动id查询
        PromotionSeckill promotionSeckill = baseMapper.selectById(promotionId);
        if (Objects.isNull(promotionSeckill)) {
            Asserts.failed("秒杀活动不存在！");
        }
        //2. 判断秒杀活动的状态
        if (promotionSeckill.getStatus() == PromotionStatus.WAIT_STATUS) {
            Asserts.failed("秒杀活动暂未开始!");
        }
        if (promotionSeckill.getStatus() == PromotionStatus.OVER_STATUS) {
            Asserts.failed("秒杀活动已经结束！");

        }

        //3. 同一个用户只能秒杀一个类型的商品，这里先做判断
        // sismember seckill:user:u100 12
        Boolean isMember =
                redisTemplate.opsForSet().isMember(RedisConstant.SECKILL_USER + userId, promotionId);
        if (isMember) {
            Asserts.failed("商品不能重复抢购！");
        }

        //4、扣减库存，通过leftPop弹出redis中list集合中的库存数据
        Integer productId = (Integer) redisTemplate.opsForList()
                .leftPop(RedisConstant.SECKILL_COUNT + promotionId);
        if (Objects.isNull(productId)) {
            Asserts.failed("商品已经售完！");
        }

        //5、生成订单, 通过openfeign远程调用订单微服务
        // ........
        // ........
        //5.1 根据商品id查询
        Product product = productMapper.selectById(productId);
        //5.2 封装opfenfeign远程调用dto对象
        OrderDto orderDto = new OrderDto();
        orderDto.setUserId(userId);
        orderDto.setProductId(productId);
        orderDto.setProductPic(product.getPic());
        orderDto.setProductName(product.getTitle());
        orderDto.setPrice(product.getPrice());
        orderDto.setPromotionPrice(product.getPromotionPrice());
        //5.3 openfeign的远程调用
        Result<String> feignResult = orderFeginClient.createOrder(orderDto);

        //6、生成订单后，要记录当前用户参与的秒杀活动商品
        redisTemplate.opsForSet().add(RedisConstant.SECKILL_USER+userId,promotionId);

        //7、返回
        OrderVo orderVo = new OrderVo();
        orderVo.setUserId(userId);
        orderVo.setOrderSn(feignResult.getData());
        return orderVo;
    }

    @Override
    public Integer payOrder(OrderPayDto orderDto) {
        //更新订单状态，调用订单微服务
        Result<Integer> result = orderFeginClient.update(orderDto.getOrderSn());
        if(result.getCode() == 500){
            Asserts.failed(result.getMessage());
        }
        //扣减库存
        int count = baseMapper.updateStore(orderDto.getPromotionId());
        if(count<=0){
            Asserts.failed("库存扣减失败");
        }
        return result.getData();
    }

    @Override
    public PaymentVo confirmOrder(OrderPayDto orderPayDto) {
        checkOrder(orderPayDto);

        //查询商品ID
        LambdaQueryWrapper<PromotionSeckill> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(PromotionSeckill::getProductId);
        queryWrapper.eq(PromotionSeckill::getId,orderPayDto.getPromotionId());

        PromotionSeckill ps = baseMapper.selectOne(queryWrapper);
        orderPayDto.setProductId(ps.getProductId());//商品Id，如果订单失效需要还原redis库存
        //发送消息到MQ
        orderProducer.sendOrder(orderPayDto);
        return PaymentVo.builder()
                .orderSn(orderPayDto.getOrderSn())
                .promotionId(orderPayDto.getPromotionId())
                .totalAmount(orderPayDto.getTotalAmount())
                .userId(orderPayDto.getUserId())
                .build();
    }

    private void checkOrder(OrderPayDto orderPayDto) {
        Result<com.wnxy.pms.order.client.vo.OrderVo> result  =
                orderFeginClient.getOrderBySn(orderPayDto.getOrderSn());
        com.wnxy.pms.order.client.vo.OrderVo vo = result.getData();

        //订单状态：0->待付款；1->待发货；2->已发货；3->已完成；4->已关闭；5->无效订单
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_INVALID)){//5
            Asserts.failed("订单已失效");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_CLOSED)){//4
            Asserts.failed("订单已经关闭");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_FINISH)){//3
            Asserts.failed("订单已经完成");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_SHIP)){//2
            Asserts.failed("订单已经发货");
        }
        if(vo.getStatus().equals(OrderConstant.ORDER_STATUS_UNSHIP)){//1 ?
            Asserts.failed("订单待发货");
        }
    }
}





















